#!/bin/sh

TOOLSDIR='tools'
PACKAGESDIR='packages'
WORKSPACEDIR='workspace'
TOOLSROOTDIR='root'
KEYRING='keyring.gpg'
GNUMIRROR='ftp.gnu.org'

packages=' '

package_binutils_protocols=' https http ftp '
package_binutils_server=$GNUMIRROR
package_binutils_remotedir='/gnu/binutils'
package_binutils_filename='binutils-2.30'
package_binutils_extensions=' tar.xz tar.lz tar.bz2 tar.gz '
package_binutils_recipe='setup_binutils'

package_gawk_protocols=' https http ftp '
package_gawk_server=$GNUMIRROR
package_gawk_remotedir='/gnu/gawk'
package_gawk_filename='gawk-4.2.1'
package_gawk_extensions=' tar.xz tar.lz tar.gz '
package_gawk_recipe='setup_gawk'

package_gcc_protocols=' https http ftp '
package_gcc_server=$GNUMIRROR
package_gcc_remotedir='/gnu/gcc/gcc-7.3.0'
package_gcc_filename='gcc-7.3.0'
package_gcc_extensions=' tar.xz tar.gz '
package_gcc_recipe='setup_gcc'

package_grub_protocols=' https http ftp '
package_grub_server=$GNUMIRROR
package_grub_remotedir='/gnu/grub'
package_grub_filename='grub-2.02'
package_grub_extensions=' tar.xz tar.gz '
package_grub_recipe='setup_grub'

package_nasm_protocols=' http '
package_nasm_server='www.nasm.us'
package_nasm_remotedir='/pub/nasm/releasebuilds/2.13.03'
package_nasm_filename='nasm-2.13.03'
package_nasm_extensions=' tar.xz tar.bz2 tar.gz zip '
package_nasm_recipe='setup_nasm'

package_xorriso_protocols=' https http ftp '
package_xorriso_server=$GNUMIRROR
package_xorriso_remotedir='/gnu/xorriso'
package_xorriso_filename='xorriso-1.4.8'
package_xorriso_extensions=' tar.gz '
package_xorriso_recipe='setup_xorriso'

setup_binutils() {
    cd 'binutils-2.30' && ./configure "--prefix=$PREFIX" --target=i686-elf --disable-nls && make $MAKEFLAGS && make install
}

setup_gawk() {
    cd 'gawk-4.2.1' && ./configure "--prefix=$PREFIX" && make $MAKEFLAGS && make install
}

setup_gcc() {
    cd 'gcc-7.3.0' && mkdir -p build && cd build \
        && ../configure "--prefix=$PREFIX" --target=i686-elf --enable-languages=c --without-headers --disable-nls --disable-libssp \
        && make $MAKEFLAGS all-gcc && make $MAKEFLAGS all-target-libgcc \
        && make install-gcc && make install-target-libgcc
}

setup_grub() {
    cd 'grub-2.02' && ./configure "--prefix=$PREFIX" && make $MAKEFLAGS && make install
}

setup_nasm() {
    cd 'nasm-2.13.03' && ./configure "--prefix=$PREFIX" && make $MAKEFLAGS && make install
}

setup_xorriso() {
    cd 'xorriso-1.4.8' && ./configure "--prefix=$PREFIX" && make $MAKEFLAGS && make install
}

download() {
    download_url="$1://$2/$3"

    if [ -n "$AXEL" ]
    then
        "$AXEL" -o "$4" "$download_url"
    elif [ -n "$WGET" ]
    then
        "$WGET" -O "$4" "$download_url"
    elif [ -n "$CURL" ]
    then
        "$CURL" -L -o "$4" "$download_url"
    elif [ -n "$PFTP" ] && [ "$1" = "ftp" ]
    then
        separator=`expr index + "$2" + :`

        if  [ $separator -ne 0 ]
        then
            host=`expr substr + "$2" 1 \( "$separator" - 1 \)`
            port=`expr substr + "$2" \( $separator + 1 \) \( length + "$2" \)`
        else
            host="$2"
            port=""
        fi

        "$PFTP" -n $host $port <<EOF
user ftp
binary
get "$remotepath" "$localpath"
quit
EOF
    else
        printf 'No suitable program available to download "%s". Giving up.\n' "$url" 1>&2
        exit 1
    fi
}

extract() {
    if expr + "$1" : '.*\.tar.*' 1>/dev/null
    then
        "$TAR" -C "$2" -x -f "$1"
    elif expr + "$1" : '.*\.zip$' 1>/dev/null
    then
        "$UNZIP" "$1" -d "$2"
    fi
}

[ -d "$TOOLSDIR" ] || mkdir "$TOOLSDIR" || exit 1
cd "$TOOLSDIR" || exit 1

[ -d "$PACKAGESDIR" ]  || mkdir "$PACKAGESDIR"  || exit 1
[ -d "$WORKSPACEDIR" ] || mkdir "$WORKSPACEDIR" || exit 1
[ -d "$TOOLSROOTDIR" ] || mkdir "$TOOLSROOTDIR" || exit 1

export PATH="$PWD/$TOOLSROOTDIR/bin:$PATH"

AXEL=`command -v axel`
WGET=`command -v wget`
CURL=`command -v curl`
FTP=`command -v ftp`
PFTP=`command -v pftp` || ([ -n "$FTP" ] && PFTP="$FTP -p")
TAR=`command -v tar`
UNZIP=`command -v unzip`

if ! GPG=`command -v gpg`
then
    echo 'GNU Privacy Guard is required to verify signatures. Please install it.' 1>&2
    exit 1
fi

ARCHIVES=' '

if [ -n "$TAR" ]
then
    for comp in xz.xz lzip.lz bzip2.bz2 gzip.gz
    do
        program=`expr substr "$comp" 1 \( index + "$comp" . - 1 \)`
        extension=`expr substr "$comp" \( index + "$comp" . + 1 \) \( length $comp \)`
        command -v "$program" 1>/dev/null && ARCHIVES="${ARCHIVES}tar.$extension "
    done
fi

[ -n "$UNZIP" ] && ARCHIVES="${ARCHIVES}zip "

echo 'Detecting installed packages...' 1>&2
command -v gawk || packages="${packages}gawk "
command -v i686-elf-ld || packages="${packages}binutils "
command -v i686-elf-gcc || packages="${packages}gcc "
command -v grub-mkrescue || packages="${packages}grub "
command -v nasm || packages="${packages}nasm "
command -v xorriso || packages="${packages}xorriso "

MAKEFLAGS="$MAKEFLAGS -j `nproc`"

for package in $packages
do
    printf 'Installing package %s\n' "$package" 1>&2
    [ -d "$WORKSPACEDIR/$package" ] || mkdir "$WORKSPACEDIR/$package" || exit 1

    unset packagefile

    eval "protocols=\"\$package_${package}_protocols\"\
          server=\"\$package_${package}_server\"\
          remotedir=\"\$package_${package}_remotedir\"\
          filename=\"\$package_${package}_filename\"\
          extensions=\"\$package_${package}_extensions\"\
          recipe=\"\$package_${package}_recipe\""

    for ext in $extensions
    do
        printf '%s' "$ARCHIVES" | grep -q -F " $ext " || continue

        file="${filename}.$ext"
        url="$remotedir/$file"

        if ! [ -f "$PACKAGESDIR/$file" ]
        then
            success=false

            for protocol in $protocols
            do
                printf 'Downloading %s from %s://%s/%s\n' "$file" "$protocol" "$server" "$url" 1>&2
                if download "$protocol" "$server" "$url" "$PACKAGESDIR/$file"
                then
                    success=true
                    break
                fi
            done

            if ! $success
            then
                echo 'Download failed.' 1>&2
                continue
            fi
        fi

        packagefile="$PACKAGESDIR/$file"
        break;
    done

    if [ -z "$packagefile" ]
    then
        printf 'No files could be downloaded and/or extracted to install package %s. Giving up.\n' "$package" 1>&2
        exit 1
    fi

    if ! [ -f ${packagefile}.sig ]
    then
        printf 'Retrieving signature %s\n' "${packagefile}.sig" 1>&2
        if ! download "$protocol" "$server" "${url}.sig" "${packagefile}.sig"
        then
            printf 'Could not retrieve the signature for %s. Giving up.\n' "$packagefile" 1>&2
            exit 1
        fi
    fi

    printf 'Verifying signature %s\n' "${packagefile}.sig" 1>&2
    if ! "$GPG" --no-default-keyring --keyring "$PWD/$KEYRING" --verify "${packagefile}.sig" "$packagefile"
    then
        printf 'bad\nCould not verify the signature for %s. Giving up.\n' "$packagefile" 1>&2
        exit 1
    fi

    printf 'Extracting archive %s\n' "$file" 1>&2
    if ! extract "$packagefile" "$WORKSPACEDIR/$package"
    then
        printf 'The package archive %s could not be extracted. Giving up.\n' "$packagefile" 1>&2
        exit 1
    fi

    oldwd="$PWD"
    export PREFIX="$PWD/$TOOLSROOTDIR"
    cd "$WORKSPACEDIR/$package"
    $recipe
    errorcode=$?
    cd "$oldwd"

    if [ "$errorcode" -ne 0 ]
    then
        printf 'Errors occurred while building package %s. Giving up.\n' "$package" 1>&2
        exit 1
    fi
done

echo 'Done installing packages' 1>&2
